//
// Created on 2025/11/4.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef PRE_EXPORT_CODEC_COMMON_H
#define PRE_EXPORT_CODEC_COMMON_H
#include <filesystem>
#include <mutex>
#include <queue>
#include <string>
#include <sys/stat.h>

#include <multimedia/player_framework/native_avformat.h>
#include <multimedia/player_framework/native_avbuffer.h>

#include <hilog/log.h>

#undef LOG_DOMAIN
#define LOG_DOMAIN 0x0000000

#define PRE_EXPORT_LOG(func, fmt, args...)                                                                         \
    do {                                                                                                               \
        (void)func(LOG_APP, "{%{public}s():%{public}d} " fmt, __FUNCTION__, __LINE__, ##args);                         \
    } while (0)

#define PRE_EXPORT_LOGF(fmt, ...) PRE_EXPORT_LOG(OH_LOG_FATAL, fmt, ##__VA_ARGS__)
#define PRE_EXPORT_LOGE(fmt, ...) PRE_EXPORT_LOG(OH_LOG_ERROR, fmt, ##__VA_ARGS__)
#define PRE_EXPORT_LOGW(fmt, ...) PRE_EXPORT_LOG(OH_LOG_WARN, fmt, ##__VA_ARGS__)
#define PRE_EXPORT_LOGI(fmt, ...) PRE_EXPORT_LOG(OH_LOG_INFO, fmt, ##__VA_ARGS__)
#define PRE_EXPORT_LOGD(fmt, ...) PRE_EXPORT_LOG(OH_LOG_DEBUG, fmt, ##__VA_ARGS__)

enum class ResultCode {
    OK,
    ERROR,
    PARAM_ERROR,
    CONFIGURE_ERROR,
    CACHE_INVALID,
    SYSTEM_ERROR,
    TIMEOUT_ERROR,
};

enum class ExportType {
    PRE_EXPORT,
    EXPORT,
};

struct CacheInfo
{
    // for cache
    bool frameInput = false;
    uint8_t *inBuff = nullptr;
    bool cached = false;
    std::string cachePath = "";
    uint32_t width = 0;
    uint32_t height = 0;
    bool isIFrame = false;
    
    CacheInfo() {
        PRE_EXPORT_LOGI("create %{public}p", this);
    };
    ~CacheInfo() {
        PRE_EXPORT_LOGI("delete %{public}p", this);
    };
    bool isReadyToCache() { return frameInput && (inBuff != nullptr); }
    bool isCached() { return cached && (cachePath != ""); }
    void toReCache() { 
        if (isCached() && !isReadyToCache()) {
            frameInput = false;
            free(inBuff);
            inBuff = nullptr;
        }
        cached = false;
        cachePath = "";
    }
    
    // for codec
    CacheInfo(uint32_t index, OH_AVBuffer *buffer): index(index), buffer(buffer), isValid(true) {}
    // 回调buffer。
    OH_AVBuffer *buffer = nullptr;
    // 回调buffer对应的index。
    uint32_t index = 0;
    // 判断当前buffer信息是否有效。
    bool isValid = true;
};

class CodecBufferQueue {
public:
    // 将回调buffer的信息传入队列。
    void Enqueue(std::shared_ptr<CacheInfo> bufferInfo)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        bufferQueue_.push(bufferInfo);
        cond_.notify_all();
    }

    // 获取回调buffer的信息。
    std::shared_ptr<CacheInfo> Dequeue(int32_t timeoutMs = 1000)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        (void)cond_.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this]() { return !bufferQueue_.empty(); });
        if (bufferQueue_.empty()) {
            return nullptr;
        }
        std::shared_ptr<CacheInfo> bufferInfo = bufferQueue_.front();
        bufferQueue_.pop();
        return bufferInfo;
    }

    // 清空队列，之前的回调buffer设置为不可用。
    void Flush()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while (!bufferQueue_.empty()) {
            std::shared_ptr<CacheInfo> bufferInfo = bufferQueue_.front();
            // Flush、Stop、Reset、Destroy操作之后，之前回调的buffer信息设置为无效。
            bufferInfo->isValid = false;
            bufferQueue_.pop();
        }
    }
    
    bool empty()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return bufferQueue_.empty();
    }
    
    uint32_t size()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return bufferQueue_.size();
    }

private:
    std::mutex mutex_;
    std::condition_variable cond_;
    std::queue<std::shared_ptr<CacheInfo>> bufferQueue_;
};

struct CodecUserData {
    bool toStop = false;
    CodecBufferQueue inQueue;
    CodecBufferQueue outQueue;
};

class CodecCommon {
public:
    static ResultCode ReadFile(std::string &filePath, void **fileData, uint32_t *fileSize)
    {
        if (filePath == "") {
            PRE_EXPORT_LOGE("cached path empty");
            return ResultCode::ERROR;
        }
        if (!std::filesystem::exists(filePath)) {
            PRE_EXPORT_LOGE("cached file not exist");
            return ResultCode::ERROR;
        }
        struct stat st;
        if (stat(filePath.c_str(), &st) != 0) {
            PRE_EXPORT_LOGE("get file size failed");
            return ResultCode::ERROR;
        }
        FILE *pFile = fopen(filePath.c_str(), "rb");
        if (pFile == nullptr) {
            PRE_EXPORT_LOGE("open cached file failed");
            return ResultCode::ERROR;
        }
        uint32_t size = st.st_size;
        uint8_t *dataBuff = new uint8_t[size];
        if (dataBuff == nullptr) {
            PRE_EXPORT_LOGE("alloc data buff failed");
            return ResultCode::ERROR;
        }
        uint32_t readSize = fread(dataBuff, 1, size, pFile);
        if (size != readSize) {
            PRE_EXPORT_LOGE("read cached file failed");
            delete[] dataBuff;
            fclose(pFile);
            return ResultCode::ERROR;
        }
        *fileData = dataBuff;
        *fileSize = size;
        fclose(pFile);
        return ResultCode::OK;
    }
};

#endif //PRE_EXPORT_CODEC_COMMON_H
